package gtpengine

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"log"
	"os/exec"
	"strings"
)

type GTPConnection struct {
	cmd     *exec.Cmd
	infile  io.WriteCloser
	outfile io.ReadCloser
	errfile io.ReadCloser
	ShowLog bool
	wait    chan int
}

// NewGTPConnection 创建GTP连接器
func NewGTPConnection(cmd string, args ...string) (*GTPConnection, error) {
	conn := GTPConnection{ShowLog: false, wait: make(chan int, 1)}
	conn.cmd = exec.Command(cmd, args...)
	inf, err := conn.cmd.StdinPipe() //获取输入管道，后续通过管道与AI进行交互
	if err != nil {
		return nil, err
	}
	conn.infile = inf
	outf, err := conn.cmd.StdoutPipe() //获取输入管道，在输入管道有命令进入时，通过输出管道获取命令返回值
	if err != nil {
		return nil, err
	}
	conn.outfile = outf
	errf, err := conn.cmd.StderrPipe() //获取输入管道，在输入管道有命令进入时，通过输出管道获取命令返回值
	if err != nil {
		return nil, err
	}
	conn.errfile = errf
	conn.cmd.Start() //开始命令，并且程序继续执行
	//异步等待，不阻塞程序执行
	go func() {
		conn.cmd.Wait()
	}()
	return &conn, nil
}

// 完整PATH,自动解析为对应命令行
func NewGTPConnectionByPath(path string) (*GTPConnection, error) {
	s1 := strings.Fields(path)
	command := s1[0]
	return NewGTPConnection(command, s1[1:]...)
}

func (g *GTPConnection) SettingLog(w io.Writer) {
	g.ShowLog = true
	//g.logger = log.New(w, "", 0)
}
func (g *GTPConnection) WriteLog(info ...interface{}) {
	if g.ShowLog {
		log.Println(info)
	}
}

// Exec 通过管道执行命令并得到返回值
func (g *GTPConnection) Exec(cmd string) (string, error) {
	//通过输入管道执行命令
	g.WriteLog(fmt.Sprintf("input>> %s", cmd))
	g.infile.Write([]byte(fmt.Sprintf("%s\n", cmd)))
	//读取输出管道的值，因为输出管道是一个io.ReadCloser,所以我们可以通过bufio.NewReader()来读取返回值
	reader := bufio.NewReader(g.outfile)
	result := ""
	for {
		line, err := reader.ReadString('\n')
		if err != nil || io.EOF == err {
			break
		}
		if (strings.Contains(result, "=") || strings.Contains(result, "?")) && (line == "\n" || line == "\r\n") {
			break
		}
		if line != "\n" && line != "\r\n" {
			result += line
		}
	}
	g.WriteLog(fmt.Sprintf("output>> %s", result))
	res := strings.Split(result, "")
	l := len(res)
	if l > 0 {
		if res[l-1] == "\n" {
			result = strings.Join(res[:l-1], "")
		}
		if len(result) == 0 {
			return "", errors.New("ERROR length=0")
		}
		if res[0] == "=" {
			return strings.TrimSpace(strings.Join(res[2:], "")), nil
		}
		if res[0] == "?" {
			return "", errors.New(strings.Join(res[2:], ""))
		}
	}
	return "", errors.New("ERROR: Unrecognized answer: " + result)
}

func (g *GTPConnection) ListenInfo(cb func(i string)) {
	reader := bufio.NewReader(g.errfile)

	for {
		select {
		case <-g.wait:
			g.WriteLog("关闭")
			return
		default:
			line, _ := reader.ReadString('\n')
			cb(line)
		}
	}
}

// Close 释放GTP资源
func (g GTPConnection) Close() {
	g.infile.Close()
	g.outfile.Close()
	g.errfile.Close()
	g.wait <- 1
}
